using System;
using Microsoft.IdentityModel.Tokens;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.IdentityModel.Tokens.Jwt;

namespace QDJwt.Token
{
    public class TokenProviderOptions
    {
        public string Path { get; set; } = "/token";

        public string Issuer { get; set; }

        public string Audience { get; set; }

        public TimeSpan Expiration { get; set; } = TimeSpan.FromHours(1);

        public SigningCredentials SigningCredentials { get; set; }
    }
    public class TokenGenerator
    {
        private TokenProviderOptions Options { get; }
        public TokenGenerator(TokenProviderOptions options)
        {
            Options = options;

        }
        public async Task<string> GenerateToken(iUserInfo user,long updateTime)
        {
            var identity =await GetIdentity(user,updateTime);
            var now = DateTime.UtcNow;

            // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
            // You can add other claims here, if you want:

            // Create the JWT and write it to a string
            var jwt = new JwtSecurityToken(
              issuer: Options.Issuer,
              audience: Options.Audience,
              claims: identity.Claims.ToArray(),
              notBefore: now,
              expires: now.Add(Options.Expiration),
              signingCredentials: Options.SigningCredentials);

            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

            return encodedJwt;
        
        }

        public async Task<ClaimsIdentity> GetIdentity(iUserInfo user,long updateTime)
        {
            // DON'T do this in production, obviously!
            if(user!= null)
            {
                var identity = await Task.FromResult(new ClaimsIdentity(new System.Security.Principal.GenericIdentity(user.GetUserName(), "Token"), new Claim[] { }));
                var now = DateTime.UtcNow;
                var claims = new List<Claim>()
                {
                    new Claim(JwtRegisteredClaimNames.Sub, user.GetUserName().ToString()),
                     new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                     new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(now).ToString(), ClaimValueTypes.Integer64),
                    new Claim(ClaimTypes.Sid,user.GetUserID()),
                     new Claim("UserLoginTime",updateTime.ToString()),
                };
                IList<iRole> roles = user.GetRoleInfos();
                if(roles != null && roles.Count>0)
                {

                    // StringBuilder sb = new StringBuilder();
                    // foreach(UserRole role in roles)
                    // {
                    //     sb.Append(role.RoleName);
                    //     sb.Append(",");
                    // }
                    // sb.Remove(sb.Length-1,1);
                    // claims.Add(new Claim(ClaimTypes.Role,sb.ToString()));
                    foreach(iRole role in roles)
                    {
                         claims.Add(new Claim(ClaimTypes.Role,role.GetRoleName()));
                    }
                }
                identity.AddClaims(claims);
                return identity;
            }
            else 
            {
                return null;
            }
           
        }
        public static long ToUnixEpochDate(DateTime date)
          => (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
    }
}